package user.zc.config;

import user.zc.config.user.config.UserConfig;
import user.zc.config.value.Key;
import user.zc.config.value.KeyValue;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @author zhouchuang
 * @date 2023/8/10 14:52
 */
public enum ValueType {
    Value{
        @Override
        public <T extends Key> String join(Map.Entry<String, T> entry) {
            return entry.getKey()+"\r\n";
        }

        @Override
        public <T extends Key> T split(String line, Class<? extends T> clazz) {
            return (T)new Key(line);
        }
    },KeyValue{
        @Override
        public <T extends Key> String join(Map.Entry<String, T> entry) {
            return entry.getKey()+ UserConfig.DELIMITER+((KeyValue)entry.getValue()).getValue()+"\r\n";
        }

        @Override
        public <T extends Key> T split(String line, Class<? extends T> clazz) {
            return (T)new KeyValue(line.split(UserConfig.DELIMITER)[0],line.split(UserConfig.DELIMITER)[1]);
        }
    },KeyEntity{
        @Override
        public <T extends Key> String join(Map.Entry<String, T> entry) {
            List<String> lines = new ArrayList<String>(){{add(entry.getKey());}};
            //先吧所有属性都拿出来再排序，保证读取顺序一致性
            List<String> names = getOrderedFields(entry.getValue().getClass());
            names.forEach(name->{
                try {
                    Field field = entry.getValue().getClass().getDeclaredField(name);
                    field.setAccessible(true);
                    Object o = field.get(entry.getValue());
                    lines.add(o.toString());
                } catch (Exception e) {
                    e.printStackTrace();
                }
            });
            return String.join(UserConfig.DELIMITER,lines)+"\r\n";
        }

        @Override
        public <T extends Key> T split(String line, Class<? extends T> clazz) {
            try {
                List<String> names = getOrderedFields(clazz);
                T instance  = clazz.newInstance();
                instance.setKey(line.split(UserConfig.DELIMITER)[0]);
                String[] values = line.split(UserConfig.DELIMITER);
                for (int i = 0; i < names.size(); i++) {
                    Field field = clazz.getDeclaredField(names.get(i));
                    if(field!=null){
                        field.setAccessible(true);
                        if(field.getType().isAssignableFrom(String.class)){
                            field.set(instance,values[i+1]);
                        }else if(field.getType().isAssignableFrom(Integer.class)){
                            field.set(instance,Integer.parseInt(values[i+1]));
                        }else if(field.getType().isAssignableFrom(Boolean.class)){
                            field.set(instance,Boolean.parseBoolean(values[i+1]));
                        }
                    }
                }
                return instance;
            } catch (Exception e) {
                e.printStackTrace();
            }
            return null;
        }
        private List<String> getOrderedFields(Class<?> clazz){
            return Arrays.stream(clazz.getDeclaredFields()).map(f->f.getName()).sorted().collect(Collectors.toList());
        }
    };
    public abstract <T extends Key> String join(Map.Entry<String,T> entry);
    public abstract <T extends Key> T split(String line, Class<? extends T> clazz);
}
